home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / daemons / bsd-ftpd.000 / bsd-ftpd / bsd.ftpd / glob.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-09  |  19.3 KB  |  854 lines

  1. /*    $NetBSD: glob.c,v 1.5 1995/02/27 04:13:35 cgd Exp $    */
  2.  
  3. /*
  4.  * Copyright (c) 1989, 1993
  5.  *    The Regents of the University of California.  All rights reserved.
  6.  *
  7.  * This code is derived from software contributed to Berkeley by
  8.  * Guido van Rossum.
  9.  *
  10.  * Redistribution and use in source and binary forms, with or without
  11.  * modification, are permitted provided that the following conditions
  12.  * are met:
  13.  * 1. Redistributions of source code must retain the above copyright
  14.  *    notice, this list of conditions and the following disclaimer.
  15.  * 2. Redistributions in binary form must reproduce the above copyright
  16.  *    notice, this list of conditions and the following disclaimer in the
  17.  *    documentation and/or other materials provided with the distribution.
  18.  * 3. All advertising materials mentioning features or use of this software
  19.  *    must display the following acknowledgement:
  20.  *    This product includes software developed by the University of
  21.  *    California, Berkeley and its contributors.
  22.  * 4. Neither the name of the University nor the names of its contributors
  23.  *    may be used to endorse or promote products derived from this software
  24.  *    without specific prior written permission.
  25.  *
  26.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  27.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  30.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  32.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  33.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  35.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  36.  * SUCH DAMAGE.
  37.  */
  38.  
  39. #if defined(LIBC_SCCS) && !defined(lint)
  40. #if 0
  41. static char sccsid[] = "@(#)glob.c    8.3 (Berkeley) 10/13/93";
  42. #else
  43. static char rcsid[] = "$NetBSD: glob.c,v 1.5 1995/02/27 04:13:35 cgd Exp $";
  44. #endif
  45. #endif /* LIBC_SCCS and not lint */
  46.  
  47. /*
  48.  * glob(3) -- a superset of the one defined in POSIX 1003.2.
  49.  *
  50.  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
  51.  *
  52.  * Optional extra services, controlled by flags not defined by POSIX:
  53.  *
  54.  * GLOB_QUOTE:
  55.  *    Escaping convention: \ inhibits any special meaning the following
  56.  *    character might have (except \ at end of string is retained).
  57.  * GLOB_MAGCHAR:
  58.  *    Set in gl_flags if pattern contained a globbing character.
  59.  * GLOB_NOMAGIC:
  60.  *    Same as GLOB_NOCHECK, but it will only append pattern if it did
  61.  *    not contain any magic characters.  [Used in csh style globbing]
  62.  * GLOB_ALTDIRFUNC:
  63.  *    Use alternately specified directory access functions.
  64.  * GLOB_TILDE:
  65.  *    expand ~user/foo to the /home/dir/of/user/foo
  66.  * GLOB_BRACE:
  67.  *    expand {1,2}{a,b} to 1a 1b 2a 2b 
  68.  * gl_matchc:
  69.  *    Number of matches in the current invocation of glob.
  70.  */
  71.  
  72. #include "glob.h"
  73.  
  74. #include <sys/param.h>
  75. #include <sys/stat.h>
  76.  
  77. #include <ctype.h>
  78. #include <dirent.h>
  79. #include <errno.h>
  80. #include <pwd.h>
  81. #include <stdio.h>
  82. #include <stdlib.h>
  83. #include <string.h>
  84. #include <unistd.h>
  85.  
  86. #define    DOLLAR        '$'
  87. #define    DOT        '.'
  88. #define    EOS        '\0'
  89. #define    LBRACKET    '['
  90. #define    NOT        '!'
  91. #define    QUESTION    '?'
  92. #define    QUOTE        '\\'
  93. #define    RANGE        '-'
  94. #define    RBRACKET    ']'
  95. #define    SEP        '/'
  96. #define    STAR        '*'
  97. #define    TILDE        '~'
  98. #define    UNDERSCORE    '_'
  99. #define    LBRACE        '{'
  100. #define    RBRACE        '}'
  101. #define    SLASH        '/'
  102. #define    COMMA        ','
  103.  
  104. #ifndef DEBUG
  105.  
  106. #define    M_QUOTE        0x8000
  107. #define    M_PROTECT    0x4000
  108. #define    M_MASK        0xffff
  109. #define    M_ASCII        0x00ff
  110.  
  111. typedef u_short Char;
  112.  
  113. #else
  114.  
  115. #define    M_QUOTE        0x80
  116. #define    M_PROTECT    0x40
  117. #define    M_MASK        0xff
  118. #define    M_ASCII        0x7f
  119.  
  120. typedef char Char;
  121.  
  122. #endif
  123.  
  124.  
  125. #define    CHAR(c)        ((Char)((c)&M_ASCII))
  126. #define    META(c)        ((Char)((c)|M_QUOTE))
  127. #define    M_ALL        META('*')
  128. #define    M_END        META(']')
  129. #define    M_NOT        META('!')
  130. #define    M_ONE        META('?')
  131. #define    M_RNG        META('-')
  132. #define    M_SET        META('[')
  133. #define    ismeta(c)    (((c)&M_QUOTE) != 0)
  134.  
  135.  
  136. static int     compare __P((const void *, const void *));
  137. static void     g_Ctoc __P((const Char *, char *));
  138. static int     g_lstat __P((Char *, struct stat *, glob_t *));
  139. static DIR    *g_opendir __P((Char *, glob_t *));
  140. static Char    *g_strchr __P((Char *, int));
  141. #ifdef notdef
  142. static Char    *g_strcat __P((Char *, const Char *));
  143. #endif
  144. static int     g_stat __P((Char *, struct stat *, glob_t *));
  145. static int     glob0 __P((const Char *, glob_t *));
  146. static int     glob1 __P((Char *, glob_t *));
  147. static int     glob2 __P((Char *, Char *, Char *, glob_t *));
  148. static int     glob3 __P((Char *, Char *, Char *, Char *, glob_t *));
  149. static int     globextend __P((const Char *, glob_t *));
  150. static const Char *     globtilde __P((const Char *, Char *, glob_t *));
  151. static int     globexp1 __P((const Char *, glob_t *));
  152. static int     globexp2 __P((const Char *, const Char *, glob_t *, int *));
  153. static int     match __P((Char *, Char *, Char *));
  154. #ifdef DEBUG
  155. static void     qprintf __P((const char *, Char *));
  156. #endif
  157.  
  158. int
  159. glob(pattern, flags, errfunc, pglob)
  160.     const char *pattern;
  161.     int flags, (*errfunc) __P((const char *, int));
  162.     glob_t *pglob;
  163. {
  164.     const u_char *patnext;
  165.     int c;
  166.     Char *bufnext, *bufend, patbuf[MAXPATHLEN+1];
  167.  
  168.     patnext = (u_char *) pattern;
  169.     if (!(flags & GLOB_APPEND)) {
  170.         pglob->gl_pathc = 0;
  171.         pglob->gl_pathv = NULL;
  172.         if (!(flags & GLOB_DOOFFS))
  173.             pglob->gl_offs = 0;
  174.     }
  175.     pglob->gl_flags = flags & ~GLOB_MAGCHAR;
  176.     pglob->gl_errfunc = errfunc;
  177.     pglob->gl_matchc = 0;
  178.  
  179.     bufnext = patbuf;
  180.     bufend = bufnext + MAXPATHLEN;
  181.     if (flags & GLOB_QUOTE) {
  182.         /* Protect the quoted characters. */
  183.         while (bufnext < bufend && (c = *patnext++) != EOS) 
  184.             if (c == QUOTE) {
  185.                 if ((c = *patnext++) == EOS) {
  186.                     c = QUOTE;
  187.                     --patnext;
  188.                 }
  189.                 *bufnext++ = c | M_PROTECT;
  190.             }
  191.             else
  192.                 *bufnext++ = c;
  193.     }
  194.     else 
  195.         while (bufnext < bufend && (c = *patnext++) != EOS) 
  196.             *bufnext++ = c;
  197.     *bufnext = EOS;
  198.  
  199.     if (flags & GLOB_BRACE)
  200.         return globexp1(patbuf, pglob);
  201.     else
  202.         return glob0(patbuf, pglob);
  203. }
  204.  
  205. /*
  206.  * Expand recursively a glob {} pattern. When there is no more expansion
  207.  * invoke the standard globbing routine to glob the rest of the magic
  208.  * characters
  209.  */
  210. static int globexp1(pattern, pglob)
  211.     const Char *pattern;
  212.     glob_t *pglob;
  213. {
  214.     const Char* ptr = pattern;
  215.     int rv;
  216.  
  217.     /* Protect a single {}, for find(1), like csh */
  218.     if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
  219.         return glob0(pattern, pglob);
  220.  
  221.     while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
  222.         if (!globexp2(ptr, pattern, pglob, &rv))
  223.             return rv;
  224.  
  225.     return glob0(pattern, pglob);
  226. }
  227.  
  228.  
  229. /*
  230.  * Recursive brace globbing helper. Tries to expand a single brace.
  231.  * If it succeeds then it invokes globexp1 with the new pattern.
  232.  * If it fails then it tries to glob the rest of the pattern and returns.
  233.  */
  234. static int globexp2(ptr, pattern, pglob, rv)
  235.     const Char *ptr, *pattern;
  236.     glob_t *pglob;
  237.     int *rv;
  238. {
  239.     int     i;
  240.     Char   *lm, *ls;
  241.     const Char *pe, *pm, *pl;
  242.     Char    patbuf[MAXPATHLEN + 1];
  243.  
  244.     /* copy part up to the brace */
  245.     for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
  246.         continue;
  247.     ls = lm;
  248.  
  249.     /* Find the balanced brace */
  250.     for (i = 0, pe = ++ptr; *pe; pe++)
  251.         if (*pe == LBRACKET) {
  252.             /* Ignore everything between [] */
  253.             for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
  254.                 continue;
  255.             if (*pe == EOS) {
  256.                 /* 
  257.                  * We could not find a matching RBRACKET.
  258.                  * Ignore and just look for RBRACE
  259.                  */
  260.                 pe = pm;
  261.             }
  262.         }
  263.         else if (*pe == LBRACE)
  264.             i++;
  265.         else if (*pe == RBRACE) {
  266.             if (i == 0)
  267.                 break;
  268.             i--;
  269.         }
  270.  
  271.     /* Non matching braces; just glob the pattern */
  272.     if (i != 0 || *pe == EOS) {
  273.         *rv = glob0(patbuf, pglob);
  274.         return 0;
  275.     }
  276.  
  277.     for (i = 0, pl = pm = ptr; pm <= pe; pm++)
  278.         switch (*pm) {
  279.         case LBRACKET:
  280.             /* Ignore everything between [] */
  281.             for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
  282.                 continue;
  283.             if (*pm == EOS) {
  284.                 /* 
  285.                  * We could not find a matching RBRACKET.
  286.                  * Ignore and just look for RBRACE
  287.                  */
  288.                 pm = pl;
  289.             }
  290.             break;
  291.  
  292.         case LBRACE:
  293.             i++;
  294.             break;
  295.  
  296.         case RBRACE:
  297.             if (i) {
  298.                 i--;
  299.                 break;
  300.             }
  301.             /* FALLTHROUGH */
  302.         case COMMA:
  303.             if (i && *pm == COMMA)
  304.                 break;
  305.             else {
  306.                 /* Append the current string */
  307.                 for (lm = ls; (pl < pm); *lm++ = *pl++)
  308.                     continue;
  309.                 /* 
  310.                  * Append the rest of the pattern after the
  311.                  * closing brace
  312.                  */
  313.                 for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
  314.                     continue;
  315.  
  316.                 /* Expand the current pattern */
  317. #ifdef DEBUG
  318.                 qprintf("globexp2:", patbuf);
  319. #endif
  320.                 *rv = globexp1(patbuf, pglob);
  321.  
  322.                 /* move after the comma, to the next string */
  323.                 pl = pm + 1;
  324.             }
  325.             break;
  326.  
  327.         default:
  328.             break;
  329.         }
  330.     *rv = 0;
  331.     return 0;
  332. }
  333.  
  334.  
  335.  
  336. /*
  337.  * expand tilde from the passwd file.
  338.  */
  339. static const Char *
  340. globtilde(pattern, patbuf, pglob)
  341.     const Char *pattern;
  342.     Char *patbuf;
  343.     glob_t *pglob;
  344. {
  345.     struct passwd *pwd;
  346.     char *h;
  347.     const Char *p;
  348.     Char *b;
  349.  
  350.     if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
  351.         return pattern;
  352.  
  353.     /* Copy up to the end of the string or / */
  354.     for (p = pattern + 1, h = (char *) patbuf; *p && *p != SLASH; 
  355.          *h++ = *p++)
  356.         continue;
  357.  
  358.     *h = EOS;
  359.  
  360.     if (((char *) patbuf)[0] == EOS) {
  361.         /* 
  362.          * handle a plain ~ or ~/ by expanding $HOME 
  363.          * first and then trying the password file
  364.          */
  365.         if ((h = getenv("HOME")) == NULL) {
  366.             if ((pwd = getpwuid(getuid())) == NULL)
  367.                 return pattern;
  368.             else
  369.                 h = pwd->pw_dir;
  370.         }
  371.     }
  372.     else {
  373.         /*
  374.          * Expand a ~user
  375.          */
  376.         if ((pwd = getpwnam((char*) patbuf)) == NULL)
  377.             return pattern;
  378.         else
  379.             h = pwd->pw_dir;
  380.     }
  381.  
  382.     /* Copy the home directory */
  383.     for (b = patbuf; *h; *b++ = *h++)
  384.         continue;
  385.     
  386.     /* Append the rest of the pattern */
  387.     while ((*b++ = *p++) != EOS)
  388.         continue;
  389.  
  390.     return patbuf;
  391. }
  392.     
  393.  
  394. /*
  395.  * The main glob() routine: compiles the pattern (optionally processing
  396.  * quotes), calls glob1() to do the real pattern matching, and finally
  397.  * sorts the list (unless unsorted operation is requested).  Returns 0
  398.  * if things went well, nonzero if errors occurred.  It is not an error
  399.  * to find no matches.
  400.  */
  401. static int
  402. glob0(pattern, pglob)
  403.     const Char *pattern;
  404.     glob_t *pglob;
  405. {
  406.     const Char *qpatnext;
  407.     int c, err, oldpathc;
  408.     Char *bufnext, patbuf[MAXPATHLEN+1];
  409.  
  410.     qpatnext = globtilde(pattern, patbuf, pglob);
  411.     oldpathc = pglob->gl_pathc;
  412.     bufnext = patbuf;
  413.  
  414.     /* We don't need to check for buffer overflow any more. */
  415.     while ((c = *qpatnext++) != EOS) {
  416.         switch (c) {
  417.         case LBRACKET:
  418.             c = *qpatnext;
  419.             if (c == NOT)
  420.                 ++qpatnext;
  421.             if (*qpatnext == EOS ||
  422.                 g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
  423.                 *bufnext++ = LBRACKET;
  424.                 if (c == NOT)
  425.                     --qpatnext;
  426.                 break;
  427.             }
  428.             *bufnext++ = M_SET;
  429.             if (c == NOT)
  430.                 *bufnext++ = M_NOT;
  431.             c = *qpatnext++;
  432.             do {
  433.                 *bufnext++ = CHAR(c);
  434.                 if (*qpatnext == RANGE &&
  435.                     (c = qpatnext[1]) != RBRACKET) {
  436.                     *bufnext++ = M_RNG;
  437.                     *bufnext++ = CHAR(c);
  438.                     qpatnext += 2;
  439.                 }
  440.             } while ((c = *qpatnext++) != RBRACKET);
  441.             pglob->gl_flags |= GLOB_MAGCHAR;
  442.             *bufnext++ = M_END;
  443.             break;
  444.         case QUESTION:
  445.             pglob->gl_flags |= GLOB_MAGCHAR;
  446.             *bufnext++ = M_ONE;
  447.             break;
  448.         case STAR:
  449.             pglob->gl_flags |= GLOB_MAGCHAR;
  450.             /* collapse adjacent stars to one, 
  451.              * to avoid exponential behavior
  452.              */
  453.             if (bufnext == patbuf || bufnext[-1] != M_ALL)
  454.                 *bufnext++ = M_ALL;
  455.             break;
  456.         default:
  457.             *bufnext++ = CHAR(c);
  458.             break;
  459.         }
  460.     }
  461.     *bufnext = EOS;
  462. #ifdef DEBUG
  463.     qprintf("glob0:", patbuf);
  464. #endif
  465.  
  466.     if ((err = glob1(patbuf, pglob)) != 0)
  467.         return(err);
  468.  
  469.     /*
  470.      * If there was no match we are going to append the pattern 
  471.      * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
  472.      * and the pattern did not contain any magic characters
  473.      * GLOB_NOMAGIC is there just for compatibility with csh.
  474.      */
  475.     if (pglob->gl_pathc == oldpathc && 
  476.         ((pglob->gl_flags & GLOB_NOCHECK) || 
  477.           ((pglob->gl_flags & GLOB_NOMAGIC) &&
  478.            !(pglob->gl_flags & GLOB_MAGCHAR))))
  479.         return(globextend(pattern, pglob));
  480.     else if (!(pglob->gl_flags & GLOB_NOSORT)) 
  481.         qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
  482.             pglob->gl_pathc - oldpathc, sizeof(char *), compare);
  483.     return(0);
  484. }
  485.  
  486. static int
  487. compare(p, q)
  488.     const void *p, *q;
  489. {
  490.     return(strcmp(*(char **)p, *(char **)q));
  491. }
  492.  
  493. static int
  494. glob1(pattern, pglob)
  495.     Char *pattern;
  496.     glob_t *pglob;
  497. {
  498.     Char pathbuf[MAXPATHLEN+1];
  499.  
  500.     /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
  501.     if (*pattern == EOS)
  502.         return(0);
  503.     return(glob2(pathbuf, pathbuf, pattern, pglob));
  504. }
  505.  
  506. /*
  507.  * The functions glob2 and glob3 are mutually recursive; there is one level
  508.  * of recursion for each segment in the pattern that contains one or more
  509.  * meta characters.
  510.  */
  511. static int
  512. glob2(pathbuf, pathend, pattern, pglob)
  513.     Char *pathbuf, *pathend, *pattern;
  514.     glob_t *pglob;
  515. {
  516.     struct stat sb;
  517.     Char *p, *q;
  518.     int anymeta;
  519.  
  520.     /*
  521.      * Loop over pattern segments until end of pattern or until
  522.      * segment with meta character found.
  523.      */
  524.     for (anymeta = 0;;) {
  525.         if (*pattern == EOS) {        /* End of pattern? */
  526.             *pathend = EOS;
  527.             if (g_lstat(pathbuf, &sb, pglob))
  528.                 return(0);
  529.         
  530.             if (((pglob->gl_flags & GLOB_MARK) &&
  531.                 pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
  532.                 || (S_ISLNK(sb.st_mode) &&
  533.                 (g_stat(pathbuf, &sb, pglob) == 0) &&
  534.                 S_ISDIR(sb.st_mode)))) {
  535.                 *pathend++ = SEP;
  536.                 *pathend = EOS;
  537.             }
  538.             ++pglob->gl_matchc;
  539.             return(globextend(pathbuf, pglob));
  540.         }
  541.  
  542.         /* Find end of next segment, copy tentatively to pathend. */
  543.         q = pathend;
  544.         p = pattern;
  545.         while (*p != EOS && *p != SEP) {
  546.             if (ismeta(*p))
  547.                 anymeta = 1;
  548.             *q++ = *p++;
  549.         }
  550.  
  551.         if (!anymeta) {        /* No expansion, do next segment. */
  552.             pathend = q;
  553.             pattern = p;
  554.             while (*pattern == SEP)
  555.                 *pathend++ = *pattern++;
  556.         } else            /* Need expansion, recurse. */
  557.             return(glob3(pathbuf, pathend, pattern, p, pglob));
  558.     }
  559.     /* NOTREACHED */
  560. }
  561.  
  562. static int
  563. glob3(pathbuf, pathend, pattern, restpattern, pglob)
  564.     Char *pathbuf, *pathend, *pattern, *restpattern;
  565.     glob_t *pglob;
  566. {
  567.     register struct dirent *dp;
  568.     DIR *dirp;
  569.     int err;
  570.     char buf[MAXPATHLEN];
  571.  
  572.     /*
  573.      * The readdirfunc declaration can't be prototyped, because it is
  574.      * assigned, below, to two functions which are prototyped in glob.h
  575.      * and dirent.h as taking pointers to differently typed opaque
  576.      * structures.
  577.      */
  578.     struct dirent *(*readdirfunc)();
  579.  
  580.     *pathend = EOS;
  581.     errno = 0;
  582.         
  583.     if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
  584.         /* TODO: don't call for ENOENT or ENOTDIR? */
  585.         if (pglob->gl_errfunc) {
  586.             g_Ctoc(pathbuf, buf);
  587.             if (pglob->gl_errfunc(buf, errno) ||
  588.                 pglob->gl_flags & GLOB_ERR)
  589.                 return (GLOB_ABEND);
  590.         }
  591.         return(0);
  592.     }
  593.  
  594.     err = 0;
  595.  
  596.     /* Search directory for matching names. */
  597.     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  598.         readdirfunc = pglob->gl_readdir;
  599.     else
  600.         readdirfunc = readdir;
  601.     while ((dp = (*readdirfunc)(dirp))) {
  602.         register u_char *sc;
  603.         register Char *dc;
  604.  
  605.         /* Initial DOT must be matched literally. */
  606.         if (dp->d_name[0] == DOT && *pattern != DOT)
  607.             continue;
  608.         for (sc = (u_char *) dp->d_name, dc = pathend; 
  609.              (*dc++ = *sc++) != EOS;)
  610.             continue;
  611.         if (!match(pathend, pattern, restpattern)) {
  612.             *pathend = EOS;
  613.             continue;
  614.         }
  615.         err = glob2(pathbuf, --dc, restpattern, pglob);
  616.         if (err)
  617.             break;
  618.     }
  619.  
  620.     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  621.         (*pglob->gl_closedir)(dirp);
  622.     else
  623.         closedir(dirp);
  624.     return(err);
  625. }
  626.  
  627.  
  628. /*
  629.  * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
  630.  * add the new item, and update gl_pathc.
  631.  *
  632.  * This assumes the BSD realloc, which only copies the block when its size
  633.  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
  634.  * behavior.
  635.  *
  636.  * Return 0 if new item added, error code if memory couldn't be allocated.
  637.  *
  638.  * Invariant of the glob_t structure:
  639.  *    Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
  640.  *    gl_pathv points to (gl_offs + gl_pathc + 1) items.
  641.  */
  642. static int
  643. globextend(path, pglob)
  644.     const Char *path;
  645.     glob_t *pglob;
  646. {
  647.     register char **pathv;
  648.     register int i;
  649.     u_int newsize;
  650.     char *copy;
  651.     const Char *p;
  652.  
  653.     newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
  654.     pathv = pglob->gl_pathv ? 
  655.             realloc((char *)pglob->gl_pathv, newsize) :
  656.             malloc(newsize);
  657.     if (pathv == NULL)
  658.         return(GLOB_NOSPACE);
  659.  
  660.     if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
  661.         /* first time around -- clear initial gl_offs items */
  662.         pathv += pglob->gl_offs;
  663.         for (i = pglob->gl_offs; --i >= 0; )
  664.             *--pathv = NULL;
  665.     }
  666.     pglob->gl_pathv = pathv;
  667.  
  668.     for (p = path; *p++;)
  669.         continue;
  670.     if ((copy = malloc(p - path)) != NULL) {
  671.         g_Ctoc(path, copy);
  672.         pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
  673.     }
  674.     pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
  675.     return(copy == NULL ? GLOB_NOSPACE : 0);
  676. }
  677.  
  678.  
  679. /*
  680.  * pattern matching function for filenames.  Each occurrence of the *
  681.  * pattern causes a recursion level.
  682.  */
  683. static int
  684. match(name, pat, patend)
  685.     register Char *name, *pat, *patend;
  686. {
  687.     int ok, negate_range;
  688.     Char c, k;
  689.  
  690.     while (pat < patend) {
  691.         c = *pat++;
  692.         switch (c & M_MASK) {
  693.         case M_ALL:
  694.             if (pat == patend)
  695.                 return(1);
  696.             do 
  697.                 if (match(name, pat, patend))
  698.                     return(1);
  699.             while (*name++ != EOS);
  700.             return(0);
  701.         case M_ONE:
  702.             if (*name++ == EOS)
  703.                 return(0);
  704.             break;
  705.         case M_SET:
  706.             ok = 0;
  707.             if ((k = *name++) == EOS)
  708.                 return(0);
  709.             if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
  710.                 ++pat;
  711.             while (((c = *pat++) & M_MASK) != M_END)
  712.                 if ((*pat & M_MASK) == M_RNG) {
  713.                     if (c <= k && k <= pat[1])
  714.                         ok = 1;
  715.                     pat += 2;
  716.                 } else if (c == k)
  717.                     ok = 1;
  718.             if (ok == negate_range)
  719.                 return(0);
  720.             break;
  721.         default:
  722.             if (*name++ != c)
  723.                 return(0);
  724.             break;
  725.         }
  726.     }
  727.     return(*name == EOS);
  728. }
  729.  
  730. /* Free allocated data belonging to a glob_t structure. */
  731. void
  732. globfree(pglob)
  733.     glob_t *pglob;
  734. {
  735.     register int i;
  736.     register char **pp;
  737.  
  738.     if (pglob->gl_pathv != NULL) {
  739.         pp = pglob->gl_pathv + pglob->gl_offs;
  740.         for (i = pglob->gl_pathc; i--; ++pp)
  741.             if (*pp)
  742.                 free(*pp);
  743.         free(pglob->gl_pathv);
  744.     }
  745. }
  746.  
  747. static DIR *
  748. g_opendir(str, pglob)
  749.     register Char *str;
  750.     glob_t *pglob;
  751. {
  752.     char buf[MAXPATHLEN];
  753.  
  754.     if (!*str)
  755.         strcpy(buf, ".");
  756.     else
  757.         g_Ctoc(str, buf);
  758.  
  759.     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  760.         return((*pglob->gl_opendir)(buf));
  761.  
  762.     return(opendir(buf));
  763. }
  764.  
  765. static int
  766. g_lstat(fn, sb, pglob)
  767.     register Char *fn;
  768.     struct stat *sb;
  769.     glob_t *pglob;
  770. {
  771.     char buf[MAXPATHLEN];
  772.  
  773.     g_Ctoc(fn, buf);
  774.     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  775.         return((*pglob->gl_lstat)(buf, sb));
  776.     return(lstat(buf, sb));
  777. }
  778.  
  779. static int
  780. g_stat(fn, sb, pglob)
  781.     register Char *fn;
  782.     struct stat *sb;
  783.     glob_t *pglob;
  784. {
  785.     char buf[MAXPATHLEN];
  786.  
  787.     g_Ctoc(fn, buf);
  788.     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  789.         return((*pglob->gl_stat)(buf, sb));
  790.     return(stat(buf, sb));
  791. }
  792.  
  793. static Char *
  794. g_strchr(str, ch)
  795.     Char *str;
  796.     int ch;
  797. {
  798.     do {
  799.         if (*str == ch)
  800.             return (str);
  801.     } while (*str++);
  802.     return (NULL);
  803. }
  804.  
  805. #ifdef notdef
  806. static Char *
  807. g_strcat(dst, src)
  808.     Char *dst;
  809.     const Char* src;
  810. {
  811.     Char *sdst = dst;
  812.  
  813.     while (*dst++)
  814.         continue;
  815.     --dst;
  816.     while((*dst++ = *src++) != EOS)
  817.         continue;
  818.  
  819.     return (sdst);
  820. }
  821. #endif
  822.  
  823. static void
  824. g_Ctoc(str, buf)
  825.     register const Char *str;
  826.     char *buf;
  827. {
  828.     register char *dc;
  829.  
  830.     for (dc = buf; (*dc++ = *str++) != EOS;)
  831.         continue;
  832. }
  833.  
  834. #ifdef DEBUG
  835. static void 
  836. qprintf(str, s)
  837.     const char *str;
  838.     register Char *s;
  839. {
  840.     register Char *p;
  841.  
  842.     (void)printf("%s:\n", str);
  843.     for (p = s; *p; p++)
  844.         (void)printf("%c", CHAR(*p));
  845.     (void)printf("\n");
  846.     for (p = s; *p; p++)
  847.         (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
  848.     (void)printf("\n");
  849.     for (p = s; *p; p++)
  850.         (void)printf("%c", ismeta(*p) ? '_' : ' ');
  851.     (void)printf("\n");
  852. }
  853. #endif
  854.